package Csp.Reader;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;

import Csp.Model.Constraint;
import Csp.Model.Csp;
import Csp.Model.Variable;

/**

Legge il csp nel formato lista:
--------------------------------------
CSP saved by JavaCSP
listformat
savingconflicts
2
4 4 

0 1 0 2 0 3 1 1 1 2 2 0 3 0 3 1 3 2
--------------------------------------

2 -> numero di variabili
4 4 -> dimensione domini per le due variabili (4 -> 0,1,2,3)
0 1 -> i primi due numeri della riga dopo i domini rappresentano quale variabili sono coinvolte nel vincolo (0 e 1)
0 2 0 3 1 1 1 2 2 0 3 0 3 1 3 2 -> sono le tuple NON valide per le due variabili considerate

 **/

public class CspReader {

	public static Csp ReadFromFile(String pathTofile){
		
		List<Variable> variables = new ArrayList<Variable>();
		Constraint[][] constraintsMatrix = null;
		HashMap<Integer,Integer> constraintsMap = new HashMap<Integer,Integer>();
		
		BufferedReader br = null;
		try {
			String line;
			br = new BufferedReader(new FileReader(pathTofile));
			int counter = 0;
			while ((line = br.readLine()) != null) {
				
				String tokens[] = line.toLowerCase().split(" ");
				
				//Variables size
				if(counter==3){
					int varSize = Integer.parseInt(tokens[0]);
					constraintsMatrix = new Constraint[varSize][varSize];
				}
				
				//Variables id & domain size
				if(counter==4){
					int id = 0;
					for (String t : tokens) {
						HashSet<Integer> domain = new HashSet<Integer>();
						for (int i = 0; i < Integer.parseInt(t); i++) {
							domain.add(i);
						}
						
						Variable v = new Variable(id++);
						v.setDomain(domain);
						variables.add(v);
					}
				}
				
				//Constraints
				if(counter>=6){
					
					Variable v1 = variables.get(Integer.parseInt(tokens[0]));
					Variable v2 = variables.get(Integer.parseInt(tokens[1]));
					
					//Nota: solo una matrice secondo v1 < v2, attenzione a quando si legge il vincolo
					
					boolean[][] matrix = new boolean[v1.getDomain().size()][v2.getDomain().size()];
					
					for (int i = 2; i < tokens.length; i+=2){
						int v1_value = Integer.parseInt(tokens[i]);
						int v2_value = Integer.parseInt(tokens[i+1]);						
						matrix[v1_value][v2_value] = true;					
					}
					
					Constraint constraint = new Constraint(v1.getId(), v2.getId(), matrix);
					constraintsMatrix[v1.getId()][v2.getId()] = constraint;
					constraintsMatrix[v2.getId()][v1.getId()] = constraint;
					
					int v1constraintsSize = constraintsMap.get(v1.getId()) == null ? 0 : constraintsMap.get(v1.getId());  
					int v2constraintsSize = constraintsMap.get(v2.getId()) == null ? 0 : constraintsMap.get(v2.getId());  
					constraintsMap.put(v1.getId(), ++v1constraintsSize);
					constraintsMap.put(v2.getId(), ++v2constraintsSize);
				}
				
				counter++;
			}
			
			return new Csp(variables, constraintsMatrix, constraintsMap);
			
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (br != null)br.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return null;
	}
	
}
